package ar.com.spsolutions.splilabrary.view.application;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.apache.wicket.authroles.authentication.AuthenticatedWebSession;
import org.apache.wicket.authroles.authorization.strategies.role.Roles;
import org.apache.wicket.injection.Injector;
import org.apache.wicket.request.Request;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.transaction.annotation.Transactional;

import ar.com.spsolutions.splibrary.general.RoleConverterService;
import ar.com.spsolutions.splibrary.services.PasswordUtils;
import ar.com.spsolutions.splibrary.services.UserService;
import ar.com.spsolutions.splibrary.user.User;

public class WebSession extends AuthenticatedWebSession {

	private static final long serialVersionUID = 1L;
	protected static final Logger LOG = Logger.getLogger(WebSession.class);
	private User user;
	@SpringBean(name = "authenticationManager")
	private transient AuthenticationManager authenticationManager;

	public WebSession(final Request request) {
		super(request);
		this.injectDependencies();
		this.ensureDependenciesNotNull();

	}

	public void setGuestCredentials() {
		if (!this.isSignedIn()) {
			final List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
			authorities.add(new GrantedAuthorityImpl(
					RoleConverterService.ROLE_GUEST));
			final AnonymousAuthenticationToken token = new AnonymousAuthenticationToken(
					"splibrary", "splibrary", authorities);
			SecurityContextHolder.getContext().setAuthentication(token);
		}
	}

	private void ensureDependenciesNotNull() {
		if (this.authenticationManager == null) {
			throw new IllegalStateException(
					"AdminSession requires an authenticationManager.");
		}
	}

	private void injectDependencies() {
		Injector.get().inject(this);
	}

	@Override
	@Transactional(readOnly = true)
	public boolean authenticate(final String username, final String password) {
		final User tmpUser = this.getUserService().findByName(username);
		if ((tmpUser == null)
				|| !new PasswordUtils().validate(tmpUser, password)) {
			return false;
		}
		SecurityContextHolder.clearContext();
		final SecurityContext context = SecurityContextHolder.getContext();
		final PreAuthenticatedAuthenticationToken token = new PreAuthenticatedAuthenticationToken(
				username, password, this.getRoleConverterService().getGrants(
						tmpUser));
		context.setAuthentication(token);
		this.setUser(tmpUser);
		return true;
	}

	@Override
	public Roles getRoles() {
		return this.getRoleConverterService().getRoleFor(this.getUser());
	}

	private RoleConverterService getRoleConverterService() {
		return this.getApp().getConverterService();
	}

	public User getUser() {
		return this.user;
	}

	public void setUser(final User user) {
		this.user = user;
	}

	public UserService getUserService() {
		return this.getApp().getGeneralService().getUserService();
	}

	private SPApplication getApp() {
		return (SPApplication) this.getApplication();
	}

	public AuthenticationManager getAuthenticationManager() {
		return this.authenticationManager;
	}

	public void setAuthenticationManager(
			final AuthenticationManager authenticationManager) {
		this.authenticationManager = authenticationManager;
	}

}
